/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.fresco.helper.utils;

import ohos.agp.animation.AnimatorValue;
import ohos.agp.animation.timelinecurves.SpringCurve;
import ohos.agp.components.Component;
import ohos.agp.components.DependentLayout;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

import com.alexvasilkov.gestures.ViewConfiguration;
import com.chinasoft_ohos.commontools.ohosext.animation.ValueAnimator;

/**
 * 拖动关闭助手
 *
 * @author dev
 * @since 2021-08-03
 */
public class DragCloseHelper {
    /**
     * 动画执行时间
     */
    private static final long DURATION = 100;

    /**
     * 滑动边界距离
     */
    private static final int MAX_EXIT_Y = 500;

    /**
     * 最小的缩放尺寸
     */
    private static final float MIN_SCALE = 0.4F;

    private ViewConfiguration viewConfiguration;

    private int maxExitY = MAX_EXIT_Y;
    private float minScale = MIN_SCALE;

    /**
     * 是否在滑动关闭中，手指还在触摸中
     */
    private boolean isSwipingToClose;

    /**
     * 上次触摸坐标
     */
    private float mLastY;
    private float mLastRawY;
    private float mLastX;
    private float mLastRawX;

    /**
     * 上次触摸手指id
     */
    private int lastPointerId;

    /**
     * 当前位移距离Y
     */
    private float mCurrentTranslationY;
    /**
     * 当前位移距离X
     */
    private float mCurrentTranslationX;

    /**
     * 上次位移距离Y
     */
    private float mLastTranslationY;
    /**
     * 上次位移距离X
     */
    private float mLastTranslationX;

    /**
     * 正在恢复原位中
     */
    private boolean isRestAnimate = false;

    /**
     * 共享元素模式
     */
    private boolean isShareElementMode = false;

    private Component parentV;
    private Component childV;
    private Component childV2;

    private OnDragCloseListener dragCloseListener;


    /**
     * 拖亲密助手
     *
     * @param context 上下文
     */
    public DragCloseHelper(Context context) {
        viewConfiguration = new ViewConfiguration();
    }

    /**
     * 设置拖动关闭监听器
     *
     * @param dragCloseListener 拖动关闭监听器
     */
    public void setDragCloseListener(OnDragCloseListener dragCloseListener) {
        this.dragCloseListener = dragCloseListener;
    }

    /**
     * 设置共享元素模式
     *
     * @param shareElementMode 分享元素模式
     */
    public void setShareElementMode(boolean shareElementMode) {
        isShareElementMode = shareElementMode;
    }

    /**
     * 设置拖拽关闭的view
     *
     * @param rlPhotoContainer
     * @param parent parentv
     * @param child childv
     */
    public void setDragCloseViews(DependentLayout rlPhotoContainer, Component parent, Component child) {
        this.parentV = rlPhotoContainer;
        this.childV = parent;
        this.childV2 = child;
    }

    /**
     * 设置最大退出距离
     *
     * @param maxExitY 马克斯exity
     */
    public void setMaxExitY(int maxExitY) {
        this.maxExitY = maxExitY;
    }

    /**
     * 设置最小缩放尺寸
     *
     * @param minScale 最小规模
     */
    public void setMinScale(float minScale) {
        this.minScale = minScale;
    }

    /**
     * 处理事件
     *
     * @param event 事件
     * @return boolean
     */
    public boolean handleEvent(TouchEvent event) {
        if (dragCloseListener != null && dragCloseListener.intercept()) {
            isSwipingToClose = false;
            return false;
        } else {
            switch (event.getAction()) {
                case TouchEvent.PRIMARY_POINT_DOWN:
                    lastPointerId = event.getPointerId(0);
                    reset(event);
                    break;
                case TouchEvent.POINT_MOVE:
                    childV2.setEnabled(false);
                    if (event.getPointerCount() > 1) {
                        if (isSwipingToClose) {
                            isSwipingToClose = false;
                            resetCallBackAnimation();
                            return true;
                        }
                        reset(event);
                        return false;
                    }
                    float xx = event.getPointerScreenPosition(0).getX();
                    float yy = event.getPointerScreenPosition(0).getY();
                    if (Math.abs(xx - mLastX) > Math.abs(yy - mLastY)) { // 水平滑动
                        childV2.setEnabled(true);
                        return false;
                    }
                    if (lastPointerId != event.getPointerId(0)) {
                        if (isSwipingToClose) {
                            resetCallBackAnimation();
                        }
                        reset(event);
                        return true;
                    }
                    float currentY = event.getPointerScreenPosition(0).getY();
                    float currentX = event.getPointerScreenPosition(0).getX();
                    if (move(event, currentY, currentX)) {
                        return true;
                    }
                    break;
                case TouchEvent.PRIMARY_POINT_UP:
                    if (pointUp()) {
                        return true;
                    }
                    childV2.setEnabled(true);
                    break;
                case TouchEvent.CANCEL:
                    if (isSwipingToClose) {
                        resetCallBackAnimation();
                        isSwipingToClose = false;
                        return true;
                    }
                    childV2.setEnabled(true);
                    break;
                default:
                    break;
            }
        }
        return false;
    }

    private boolean pointUp() {
        if (isSwipingToClose) {
            judgeConditions();
            isSwipingToClose = false;
            return true;
        }
        return false;
    }

    private void judgeConditions() {
        if (mCurrentTranslationY > maxExitY) {
            if (isShareElementMode) {
                if (dragCloseListener != null) {
                    dragCloseListener.onDragClose(true);
                }
            } else {
                exitWithTranslation(mCurrentTranslationY);
            }
        } else {
            resetCallBackAnimation();
        }
    }

    private boolean move(TouchEvent event, float currentY, float currentX) {
        if (isSwipingToClose || (Math.abs(currentY - mLastY) > 2 * viewConfiguration.getScaledTouchSlop()
            && Math.abs(currentY - mLastY) > Math.abs(currentX - mLastX) * 1.5)) {
            mLastY = currentY;
            mLastX = currentX;

            //  float currentRawY = event.getPointerScreenPosition(0).getY();
            // float currentRawX = event.getPointerScreenPosition(0).getX();
            if (!isSwipingToClose) {
                isSwipingToClose = true;
                if (dragCloseListener != null) {
                    dragCloseListener.onDragStart();
                }
            }
            mCurrentTranslationY = currentY - mLastRawY + mLastTranslationY;
            mCurrentTranslationX = currentX - mLastRawX + mLastTranslationX;

            float percent = 1 - Math.abs(mCurrentTranslationY / (maxExitY + childV.getHeight()));
            if (percent > 1) {
                percent = 1;
            } else if (percent < 0) {
                percent = 0;
            }
            parentV.getBackgroundElement().setAlpha((int) (percent * 255));
            if (dragCloseListener != null) {
                dragCloseListener.onDragging(percent);
            }
            childV.setTranslationY(mCurrentTranslationY);
            // childV.setTranslationX(mCurrentTranslationX);
            if (percent < minScale) {
                percent = minScale;
            }
            childV.setScaleX(percent);
            childV.setScaleY(percent);
            childV.postLayout();
            childV.invalidate();
            return true;
        }
        return false;
    }

    /**
     * 退出动画
     *
     * @param currentY 当前y坐标
     */
    public void exitWithTranslation(float currentY) {
        int targetValue = currentY > 0 ? childV.getHeight() : -childV.getHeight();
        ValueAnimator anim = ValueAnimator.ofFloat(mCurrentTranslationY, targetValue);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(AnimatorValue animatorValue, float fraction, Object object) {
                updateChildView(mCurrentTranslationX, (float) object);
            }
        });
        anim.addListener(new ValueAnimator.AnimatorListener() {
            @Override
            public void onAnimationStart(ValueAnimator valueAnimator) {
            }

            @Override
            public void onAnimationEnd(ValueAnimator valueAnimator) {
                if (dragCloseListener != null) {
                    dragCloseListener.onDragClose(false);
                }
            }

            @Override
            public void onAnimationStop(ValueAnimator valueAnimator) {
            }

            @Override
            public void onAnimationCancel(ValueAnimator valueAnimator) {
            }

            @Override
            public void onAnimationRepeat(ValueAnimator valueAnimator) {
            }

            @Override
            public void onAnimationPause(ValueAnimator valueAnimator) {
            }

            @Override
            public void onAnimationResume(ValueAnimator valueAnimator) {
            }
        });
        anim.setDuration(DURATION);
        anim.setInterpolator(new SpringCurve());
        anim.start();
    }

    /**
     * 重置数据
     *
     * @param event 事件
     */
    private void reset(TouchEvent event) {
        isSwipingToClose = false;
        mLastY = event.getPointerScreenPosition(0).getY();
        mLastX = event.getPointerScreenPosition(0).getX();
        mLastRawY = event.getPointerScreenPosition(0).getY();
        mLastRawX = event.getPointerScreenPosition(0).getY();
        mLastTranslationY = childV.getTranslationY();
        mLastTranslationX = childV.getTranslationX();
    }

    /**
     * 更新子视图
     *
     * @param transX transx
     * @param transY 异装癖
     */
    private void updateChildView(float transX, float transY) {
        childV.setTranslationY(transY);
        childV.setTranslationX(transX);
        float percent = Math.abs(transY / (maxExitY + childV.getHeight()));
        float scale = 1 - percent;
        if (scale < minScale) {
            scale = minScale;
        }
        childV.setScaleX(scale);
        childV.setScaleY(scale);
    }

    /**
     * 恢复到原位动画
     */
    private void resetCallBackAnimation() {
        if (isRestAnimate || mCurrentTranslationY == 0) {
            return;
        }
        final float ratio = mCurrentTranslationX / mCurrentTranslationY;
        ValueAnimator animatorY = ValueAnimator.ofFloat(mCurrentTranslationY, 0);
        animatorY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(AnimatorValue animatorValue, float fraction, Object object) {
                if (isRestAnimate) {
                    mCurrentTranslationY = (float) object;
                    mCurrentTranslationX = ratio * mCurrentTranslationY;
                    mLastTranslationY = mCurrentTranslationY;
                    mLastTranslationX = mCurrentTranslationX;
                    updateChildView(mLastTranslationX, mCurrentTranslationY);
                }
            }
        });
        animatorY.addListener(new ValueAnimator.AnimatorListener() {
            @Override
            public void onAnimationStart(ValueAnimator valueAnimator) {
                isRestAnimate = true;
            }

            @Override
            public void onAnimationEnd(ValueAnimator valueAnimator) {
                if (isRestAnimate) {
                    parentV.getBackgroundElement().setAlpha(255);
                    mCurrentTranslationY = 0;
                    mCurrentTranslationX = 0;
                    isRestAnimate = false;
                    if (dragCloseListener != null) {
                        dragCloseListener.onDragCancel();
                    }
                }
            }

            @Override
            public void onAnimationStop(ValueAnimator valueAnimator) {
            }

            @Override
            public void onAnimationCancel(ValueAnimator valueAnimator) {
            }

            @Override
            public void onAnimationRepeat(ValueAnimator valueAnimator) {
            }

            @Override
            public void onAnimationPause(ValueAnimator valueAnimator) {
            }

            @Override
            public void onAnimationResume(ValueAnimator valueAnimator) {
            }
        });
        animatorY.setDuration(DURATION);
        animatorY.start();
    }

    /**
     * 在拖动关闭监听器
     *
     * @author dev
     * @since 2021-08-03
     */
    public interface OnDragCloseListener {
        /**
         * 拦截
         *
         * @return boolean
         */
        boolean intercept();

        /**
         * 拖动开始
         */
        void onDragStart();

        /**
         * 在拖
         *
         * @param percent 百分比
         */
        void onDragging(float percent);

        /**
         * 在拖动取消
         */
        void onDragCancel();

        /**
         * 在拖动关闭
         *
         * @param isShareElementMode 是分享元素模式
         */
        void onDragClose(boolean isShareElementMode);
    }
}
